package com.duff.download.okdownload.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Process;
import android.text.TextUtils;

import com.duff.download.okdownload.DownloadError;
import com.duff.download.okdownload.DownloadStatus;
import com.duff.download.okdownload.database.operator.QueryParameter;
import com.duff.download.okdownload.model.DownloadInfo;

/**
 * author：duff
 * version：1.0.0
 * date：2017/8/27
 */
public class DownloadDBHelper extends SQLiteOpenHelper {

    private static final String TAG = "DownloadDBHelper";

    private static final int DB_VERSION_1 = 1;

    private static final int DB_VERSION = DB_VERSION_1;

    private static final String DB_NAME_DOWNLOAD = "downloads.db";
    private static final String DB_TABLE_DOWNLOAD = "downloads";

    private final Object mLock = new Object();

    private SQLiteDatabase mSQLiteDatabase = null;

    public DownloadDBHelper(Context context, String dbName) {
        super(context, TextUtils.isEmpty(dbName) ? DB_NAME_DOWNLOAD : dbName, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        mSQLiteDatabase = db;
        createTable(db);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    private void createTable(SQLiteDatabase db) {
        try {
            db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE_DOWNLOAD);
            db.execSQL("CREATE TABLE " + DB_TABLE_DOWNLOAD + "("
                    + DownloadColumns.COLUMN_TASK_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                    + DownloadColumns.COLUMN_TASK_TAG + " VARCHAR, "
                    + DownloadColumns.COLUMN_TASK_URL + " TEXT, "
                    + DownloadColumns.COLUMN_TASK_PRIORITY + " INTEGER DEFAULT " + Process.THREAD_PRIORITY_BACKGROUND + ", "
                    + DownloadColumns.COLUMN_TASK_STATUS + " INTEGER DEFAULT " + DownloadStatus.STATUS_PENDED + ", "
                    + DownloadColumns.COLUMN_TASK_TOTAL + " INTEGER DEFAULT 0, "
                    + DownloadColumns.COLUMN_TASK_DOWNLOADED + " INTEGER DEFAULT 0, "
                    + DownloadColumns.COLUMN_TASK_PATH + " TEXT, "
                    + DownloadColumns.COLUMN_TASK_NAME + " VARCHAR, "
                    + DownloadColumns.COLUMN_TASK_FILENAME + " TEXT, "
                    + DownloadColumns.COLUMN_TASK_ADD_TIME + " INTEGER DEFAULT 0, "
                    + DownloadColumns.COLUMN_TASK_MODIFY_TIME + " INTEGER DEFAULT 0, "
                    + DownloadColumns.COLUMN_TASK_ERROR + " INTEGER DEFAULT " + DownloadError.ERROR_SUCCESS + ", "
                    + DownloadColumns.COLUMN_TASK_HTTP_STATUS + " INTEGER DEFAULT 0, "
                    + DownloadColumns.COLUMN_TASK_EXTRA_1 + " VARCHAR, "
                    + DownloadColumns.COLUMN_TASK_EXTRA_2 + " VARCHAR, "
                    + DownloadColumns.COLUMN_TASK_EXTRA_3 + " VARCHAR, "
                    + DownloadColumns.COLUMN_TASK_MD5 + " TEXT);"
            );
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void alterAdd(SQLiteDatabase db, String column, String type, String defaultValue) {
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("ALTER TABLE ")
                .append(DB_TABLE_DOWNLOAD)
                .append(" ADD ")
                .append(column)
                .append(" ")
                .append(type)
                .append(TextUtils.isEmpty(defaultValue) ? "" : (" DEFAULT " + defaultValue))
                .append(";");

        db.execSQL(sqlBuilder.toString());
    }

    public void close() {
        if (mSQLiteDatabase != null) {
            mSQLiteDatabase.close();
        }
    }

    public DownloadInfo add(DownloadInfo downloadInfo) {
        if (downloadInfo == null) {
            return null;
        }
        synchronized (mLock) {
            SQLiteDatabase db = getWritableDatabase();
            long id = db.insert(DB_TABLE_DOWNLOAD, null, buildAddContentValues(downloadInfo));
            downloadInfo.setId(id);
            return downloadInfo;
        }
    }

    public DownloadInfo[] add(DownloadInfo... downloadInfos) {
        if (downloadInfos != null && downloadInfos.length > 0) {
            synchronized (mLock) {
                SQLiteDatabase db = getWritableDatabase();
                db.beginTransaction();
                for (DownloadInfo downloadInfo : downloadInfos) {
                    long id = db.insert(DB_TABLE_DOWNLOAD, null, buildAddContentValues(downloadInfo));
                    downloadInfo.setId(id);
                }
                db.setTransactionSuccessful();
                db.endTransaction();
                return downloadInfos;
            }
        }
        return null;
    }

    private ContentValues buildAddContentValues(DownloadInfo downloadInfo) {
        ContentValues contentValues = new ContentValues();
        contentValues.put(DownloadColumns.COLUMN_TASK_TAG, downloadInfo.getTag());
        contentValues.put(DownloadColumns.COLUMN_TASK_URL, downloadInfo.getUrl());
        contentValues.put(DownloadColumns.COLUMN_TASK_PATH, downloadInfo.getPath());
        contentValues.put(DownloadColumns.COLUMN_TASK_NAME, downloadInfo.getTaskName());
        contentValues.put(DownloadColumns.COLUMN_TASK_MD5, downloadInfo.getMD5());

        long addTime = System.currentTimeMillis();
        contentValues.put(DownloadColumns.COLUMN_TASK_ADD_TIME, addTime);
        contentValues.put(DownloadColumns.COLUMN_TASK_MODIFY_TIME, addTime);

        contentValues.put(DownloadColumns.COLUMN_TASK_EXTRA_1, downloadInfo.getExtra1());
        contentValues.put(DownloadColumns.COLUMN_TASK_EXTRA_1, downloadInfo.getExtra2());
        contentValues.put(DownloadColumns.COLUMN_TASK_EXTRA_1, downloadInfo.getExtra3());

        return contentValues;
    }

    public int delete(long downloadId) {
        synchronized (mLock) {
            SQLiteDatabase db = getWritableDatabase();

            int num = db.delete(DB_TABLE_DOWNLOAD, DownloadColumns.COLUMN_TASK_ID + "=?"
                    , new String[]{String.valueOf(downloadId)});

            return num;
        }
    }

    public int delete(long... downloadIds) {
        synchronized (mLock) {
            SQLiteDatabase db = getWritableDatabase();
            db.beginTransaction();

            int numberOfDeleted = 0;
            for (long id : downloadIds) {
                numberOfDeleted += db.delete(DB_TABLE_DOWNLOAD, DownloadColumns.COLUMN_TASK_ID + "=?"
                        , new String[]{String.valueOf(id)});
            }

            db.setTransactionSuccessful();
            db.endTransaction();

            return numberOfDeleted;
        }
    }

    public int delete(QueryParameter queryParameter) {
        if (queryParameter == null) {
            return -1;
        }
        synchronized (mLock) {
            SQLiteDatabase db = getWritableDatabase();

            int num = db.delete(DB_TABLE_DOWNLOAD, queryParameter.getCondition(), queryParameter.getArgs());

            return num;
        }
    }

    public int deleteAll() {
        synchronized (mLock) {
            SQLiteDatabase db = getWritableDatabase();

            int num = db.delete(DB_TABLE_DOWNLOAD, DownloadColumns.COLUMN_TASK_ID + ">?"
                    , new String[]{String.valueOf(0)});

            return num;
        }
    }


    public int update(DownloadInfo downloadInfo) {
        if (downloadInfo == null || downloadInfo.getId() <= DownloadInfo.ID_INVALID) {
            return -1;
        }
        synchronized (mLock) {
            SQLiteDatabase db = getWritableDatabase();

            int num = db.update(DB_TABLE_DOWNLOAD, downloadInfo.convert2ContentValues(), DownloadColumns.COLUMN_TASK_ID + "=?"
                    , new String[]{String.valueOf(downloadInfo.getId())});
            return num;
        }
    }

    public int update(DownloadInfo... downloadInfos) {
        if (downloadInfos != null && downloadInfos.length > 0) {
            synchronized (mLock) {
                int numberOfUpdated = 0;
                SQLiteDatabase db = getWritableDatabase();
                db.beginTransaction();

                for (DownloadInfo info : downloadInfos) {
                    numberOfUpdated += db.update(DB_TABLE_DOWNLOAD, info.convert2ContentValues(), DownloadColumns.COLUMN_TASK_ID + "=?"
                            , new String[]{String.valueOf(info.getId())});
                }

                db.setTransactionSuccessful();
                db.endTransaction();

                return numberOfUpdated;
            }
        }
        return -1;
    }

    public int update(ContentValues contentValues) {
        long id = contentValues.getAsLong(DownloadColumns.COLUMN_TASK_ID);
        if (id > 0) {
            synchronized (mLock) {
                int numberOfUpdated = 0;
                SQLiteDatabase db = getWritableDatabase();

                numberOfUpdated += db.update(DB_TABLE_DOWNLOAD, contentValues, DownloadColumns.COLUMN_TASK_ID + "=?"
                        , new String[]{String.valueOf(id)});

                return numberOfUpdated;
            }
        }
        return -1;
    }

    public int update(ContentValues contentValues, QueryParameter queryParameter) {
        if (queryParameter == null) {
            return update(contentValues);
        } else {
            synchronized (mLock) {
                int numberOfUpdated = 0;
                SQLiteDatabase db = getWritableDatabase();

                numberOfUpdated += db.update(DB_TABLE_DOWNLOAD, contentValues, queryParameter.getCondition(), queryParameter.getArgs());

                return numberOfUpdated;
            }
        }
    }

    private DownloadInfo[] queryMultiRows(Cursor cursor) {
        if (cursor != null) {
            cursor.moveToFirst();
            int size = cursor.getCount();
            DownloadInfo[] downloadInfos = new DownloadInfo[size];
            int index = 0;
            while (size > 0 && !cursor.isAfterLast()) {
                downloadInfos[index] = new DownloadInfo(cursor);
                cursor.moveToNext();
                index++;
            }
            cursor.close();
            return downloadInfos;
        }
        return null;
    }

    private DownloadInfo querySingleRow(Cursor cursor) {
        DownloadInfo downloadInfo = null;
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                cursor.moveToFirst();
                downloadInfo = new DownloadInfo(cursor);
            }
            cursor.close();
        }
        return downloadInfo;
    }

    public DownloadInfo[] queryAll() {
        synchronized (mLock) {
            SQLiteDatabase db = getReadableDatabase();
            Cursor cursor = db.query(DB_TABLE_DOWNLOAD, DownloadColumns.COLUMNS, null, null, null, null, null);
            return queryMultiRows(cursor);
        }
    }

    public DownloadInfo[] query(QueryParameter queryParameter) {
        if (queryParameter == null) {
            return queryAll();
        } else {
            synchronized (mLock) {
                SQLiteDatabase db = getReadableDatabase();
                Cursor cursor = db.query(DB_TABLE_DOWNLOAD, DownloadColumns.COLUMNS, queryParameter.getCondition()
                        , queryParameter.getArgs(), queryParameter.getGroupBy(), queryParameter.getHaving(), queryParameter.getOrderBy());
                return queryMultiRows(cursor);
            }
        }
    }

    public DownloadInfo query(long downloadId) {
        synchronized (mLock) {
            SQLiteDatabase db = getReadableDatabase();
            Cursor cursor = db.query(DB_TABLE_DOWNLOAD, DownloadColumns.COLUMNS, DownloadColumns.COLUMN_TASK_ID + "=?"
                    , new String[]{String.valueOf(downloadId)}, null, null, null);
            return querySingleRow(cursor);
        }
    }

    public DownloadInfo[] queryUnComplete() {
        synchronized (mLock) {
            SQLiteDatabase db = getReadableDatabase();
            Cursor cursor = db.query(DB_TABLE_DOWNLOAD, DownloadColumns.COLUMNS, DownloadColumns.COLUMN_TASK_STATUS + "<>?"
                    , new String[]{String.valueOf(DownloadStatus.STATUS_DOWNLOAD_COMPLETED)}, null, null, null);
            return queryMultiRows(cursor);
        }
    }

    public boolean exists(long downloadId) {
        synchronized (mLock) {
            long rowId = 0;
            SQLiteDatabase db = getReadableDatabase();

            Cursor cursor = db.query(DB_TABLE_DOWNLOAD, new String[]{DownloadColumns.COLUMN_TASK_ID}, DownloadColumns.COLUMN_TASK_ID + "=?"
                    , new String[]{String.valueOf(downloadId)}, null, null, null);
            if (cursor != null) {
                if (cursor.getCount() > 0) {
                    cursor.moveToFirst();
                    rowId = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadColumns.COLUMN_TASK_ID));
                }
                cursor.close();
            }
            return rowId > 0;
        }
    }

}
